import React, { useEffect, useMemo, useRef, useState } from 'react'
import './SliderCaptcha.css'

interface Props {
    open: boolean
    onClose: () => void
    onPassed: () => void
}

// 图片缓存管理类
class ImageCache {
    private static cache = new Map<string, string>()
    private static preloadedImages = new Set<string>()
    private static maxCacheSize = 20

    // 预加载图片
    static async preloadImage(id: number): Promise<string> {
        const url = `https://picsum.photos/id/${id}/300/170`

        // 如果已经缓存，直接返回
        if (this.cache.has(url)) {
            return this.cache.get(url)!
        }

        // 如果正在预加载，等待完成
        if (this.preloadedImages.has(url)) {
            return new Promise((resolve) => {
                const checkCache = () => {
                    if (this.cache.has(url)) {
                        resolve(this.cache.get(url)!)
                    } else {
                        setTimeout(checkCache, 50)
                    }
                }
                checkCache()
            })
        }

        return new Promise((resolve, reject) => {
            this.preloadedImages.add(url)
            const img = new Image()
            img.crossOrigin = 'anonymous'
            img.onload = () => {
                this.cache.set(url, url)
                this.preloadedImages.delete(url)
                resolve(url)
            }
            img.onerror = () => {
                this.preloadedImages.delete(url)
                // 尝试备用图片
                const altUrl = `https://picsum.photos/id/${(id + 1) % 1000}/300/170`
                this.preloadImage((id + 1) % 1000).then(resolve).catch(reject)
            }
            img.src = url
        })
    }

    // 批量预加载图片
    static async preloadBatch(count: number = 10): Promise<void> {
        const promises = []
        for (let i = 0; i < count; i++) {
            const id = Math.floor(Math.random() * 1000)
            promises.push(this.preloadImage(id))
        }
        await Promise.allSettled(promises)
    }

    // 获取随机已缓存的图片
    static getRandomCachedImage(): string | null {
        const urls = Array.from(this.cache.keys())
        if (urls.length === 0) return null
        return urls[Math.floor(Math.random() * urls.length)]
    }

    // 清理缓存
    static clearCache(): void {
        this.cache.clear()
        this.preloadedImages.clear()
    }
}

export default function SliderCaptcha({ open, onClose, onPassed }: Props) {
    const containerRef = useRef<HTMLDivElement>(null)
    const [bgUrl, setBgUrl] = useState<string>('')
    const [imgReady, setImgReady] = useState<boolean>(false)
    const [gapX, setGapX] = useState(0)
    const [dragX, setDragX] = useState(0)
    const [down, setDown] = useState(false)
    const [result, setResult] = useState<'idle' | 'ok' | 'fail'>('idle')

    const reset = async () => {
        setResult('idle')
        setDragX(0)
        setImgReady(false)

        // 优先使用缓存的图片，实现即开即显
        const cachedImage = ImageCache.getRandomCachedImage()
        if (cachedImage) {
            setBgUrl(cachedImage)
            setImgReady(true)
            setGapX(40 + Math.floor(Math.random() * 180))
            return
        }

        // 如果没有缓存，异步加载新图片
        const id = Math.floor(Math.random() * 1000)
        try {
            const url = await ImageCache.preloadImage(id)
            setBgUrl(url)
            setImgReady(true)
        } catch (error) {
            console.error('图片加载失败:', error)
            // 使用备用图片
            const fallbackUrl = `https://picsum.photos/id/${(id + 1) % 1000}/300/170`
            setBgUrl(fallbackUrl)
            setImgReady(true)
        }
        setGapX(40 + Math.floor(Math.random() * 180))
    }

    // 组件初始化时预加载图片
    useEffect(() => {
        // 预加载一批图片到缓存
        ImageCache.preloadBatch(15)
    }, [])

    useEffect(() => {
        if (open) reset()
    }, [open])

    useEffect(() => {
        const handleMove = (e: MouseEvent) => {
            if (!down) return
            const rect = containerRef.current?.getBoundingClientRect()
            if (!rect) return
            const x = Math.min(Math.max(0, e.clientX - rect.left - 20), rect.width - 40)
            setDragX(x)
        }
        const handleUp = () => {
            if (!down) return
            setDown(false)
            if (Math.abs(dragX - gapX) < 8) {
                setResult('ok')
                setTimeout(() => {
                    onPassed()
                    onClose()
                }, 400)
            } else {
                setResult('fail')
                setTimeout(() => {
                    reset()
                }, 600)
            }
        }
        window.addEventListener('mousemove', handleMove)
        window.addEventListener('mouseup', handleUp)
        return () => {
            window.removeEventListener('mousemove', handleMove)
            window.removeEventListener('mouseup', handleUp)
        }
    }, [down, dragX, gapX, onClose, onPassed])

    if (!open) return null

    return (
        <div className="sc-mask" onMouseDown={(e) => e.stopPropagation()}>
            <div className="sc-modal" ref={containerRef}>
                <div className="sc-title">拖动下方滑块完成拼图</div>
                <div className="sc-canvas" style={{ backgroundImage: imgReady ? `url(${bgUrl})` : 'none' }}>
                    <div className="sc-hole" style={{ left: gapX }} />
                    <div className="sc-piece" style={{ left: dragX, backgroundImage: imgReady ? `url(${bgUrl})` : 'none', backgroundPositionX: -gapX }} />
                </div>
                <div className={`sc-slider ${result}`}>
                    <div className="sc-track" />
                    <div
                        className="sc-thumb"
                        onMouseDown={() => setDown(true)}
                        style={{ left: dragX }}
                    >
                        |||
                    </div>
                </div>
                <div className="sc-actions">
                    <button className="sc-btn" onClick={() => reset()}>刷新</button>
                    <button className="sc-btn" onClick={onClose}>取消</button>
                </div>
            </div>
        </div>
    )
}


